<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>组合继承</h1>
    <p>组合继承（combination inheritance），有时候也叫做伪经典继承。</p>
    <p>指的是将原型链和借用构造函数的技术组合到一块，从而发挥二者之长的一种继承模式。子类既能继承父类原型的方法，又能继承父类的属性到自己的实例上。</p>
    <p>其背后的思路是使用原型链实现对原型属性和方法的继承</p>
    <p>借用构造函数来实现对实例属性的继承。</p>
    <p>这样，既通过在原型上定义方法实现了函数复用，又能够保证每个实例都有它自己的属性</p>
    <h2>缺点</h2>
    <ul>
        <li>子类原型的constructor同样会丢失。</li>
        <li>父类的构造方法会被执行两次。（apply和替换子类原型时）</li>
    </ul>
</body>
<script>
    function Parent(name) {
        this.name = name;
        this.parentName = "parentName";
        this.age = 35;
        console.log("父类构造方法")
    }

    Parent.prototype.sayParentName = function () {
        console.log("sayParentName:", this.parentName);
    }

    Parent.prototype.sayName = function () {
        console.log("sayName:", this.name);
    }

    function Child(name) {
        // 继承构造函数内部的属性
        Parent.apply(this,arguments);
        this.childName = "childName";
    }

    // 替换子类原型
    Child.prototype = new Parent("parentName");

    Child.prototype.sayChildName = function () {
        console.log("sayChildName：", this.childName);
    }


    let parent = new Parent("parentName");
    console.log(parent.parentName); // parentName
    parent.sayParentName(); // 正常调用
    parent.sayName(); // 正常调用
    // parent.sayChildName(); // 无法调用（正确）

    console.log("---------------child---------------")
    let child = new Child("奉先");
    console.log(child.age); // 35
    child.sayName(); // 正常调用 奉先
    child.sayParentName(); // 正常调用（并且可以访问到this.parentName）
    child.sayChildName(); // 正常调用
    
    console.log(child instanceof Parent); // true
</script>

</html>